package org.Yiran.timetale_re.util.cooldown;

import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.PacketDistributor;
import org.Yiran.timetale_re.network.NetworkChannel;
import org.Yiran.timetale_re.network.SCResponsePacket;

/**
 * 全局冷却管理器
 * <p>
 * 提供便捷的方法来操作冷却系统，包括设置冷却、检查冷却状态和获取剩余冷却时间。
 * 支持基于物品和基于标识符的冷却管理，并能自动同步到客户端。
 * </p>
 * 
 * @author Yiran
 * @version 1.0
 */
public class CooldownManager {

    // ==================== 冷却设置方法 ====================

    /**
     * 设置玩家物品冷却
     * <p>
     * 为指定玩家的物品设置冷却时间，并自动同步到客户端。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param itemStack 物品堆
     * @param cooldownTicks 冷却时间（tick）
     */
    public static void setCooldown(Player player, String category, ItemStack itemStack, int cooldownTicks) {
        setCooldown(player, CooldownTracker.getCooldownKey(category, itemStack), cooldownTicks);
    }

    /**
     * 设置玩家冷却
     * <p>
     * 为指定玩家设置冷却时间，并自动同步到客户端。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param identifier 标识符
     * @param cooldownTicks 冷却时间（tick）
     */
    public static void setCooldown(Player player, String category, String identifier, int cooldownTicks) {
        setCooldown(player, CooldownTracker.getCooldownKey(category, identifier), cooldownTicks);
    }

    /**
     * 设置玩家冷却
     * <p>
     * 为指定玩家设置冷却时间，并自动同步到客户端。
     * 只在服务端执行，客户端通过网络包同步数据。
     * </p>
     * 
     * @param player 玩家
     * @param key 冷却键
     * @param cooldownTicks 冷却时间（tick）
     */
    public static void setCooldown(Player player, String key, int cooldownTicks) {
        if (!(player instanceof ServerPlayer serverPlayer)) return;

        WorldCooldownManager manager = WorldCooldownManager.get();
        if (manager == null) return;

        CooldownTracker tracker = manager.getCooldownTracker(player.getUUID());
        long endTime = player.level().getGameTime() + cooldownTicks; // 使用游戏刻而不是毫秒
        tracker.setCooldown(key, endTime);
        manager.setDirty();

        // 同步到客户端
        NetworkChannel.CHANNEL.send(
                PacketDistributor.PLAYER.with(() -> serverPlayer),
                new SCResponsePacket.CooldownPacket(key, endTime)
        );
    }

    // ==================== 冷却检查方法 ====================

    /**
     * 检查玩家物品冷却是否结束
     * <p>
     * 检查指定玩家的物品冷却是否已经结束。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param itemStack 物品堆
     * @return 如果冷却结束返回true，否则返回false
     */
    public static boolean isCooldownOver(Player player, String category, ItemStack itemStack) {
        return isCooldownOver(player, CooldownTracker.getCooldownKey(category, itemStack));
    }

    /**
     * 检查玩家冷却是否结束
     * <p>
     * 检查指定玩家的冷却是否已经结束。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param identifier 标识符
     * @return 如果冷却结束返回true，否则返回false
     */
    public static boolean isCooldownOver(Player player, String category, String identifier) {
        return isCooldownOver(player, CooldownTracker.getCooldownKey(category, identifier));
    }

    /**
     * 检查玩家冷却是否结束
     * <p>
     * 检查指定玩家的冷却是否已经结束。
     * </p>
     * 
     * @param player 玩家
     * @param key 冷却键
     * @return 如果冷却结束返回true，否则返回false
     */
    public static boolean isCooldownOver(Player player, String key) {
        WorldCooldownManager manager = WorldCooldownManager.get();
        if (manager == null) return true;

        CooldownTracker tracker = manager.getCooldownTracker(player.getUUID());
        return tracker.isCooldownOver(key, player.level().getGameTime());
    }

    /**
     * 检查玩家物品冷却是否结束，如果在冷却中则播放提示声音
     * <p>
     * 检查指定玩家的物品冷却是否已经结束，如果仍在冷却中则播放提示声音。
     * 仅在服务端播放声音，避免客户端重复播放。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param itemStack 物品堆
     * @return 如果冷却结束返回true，否则返回false
     */
    public static boolean isCooldownOverWithSound(Player player, String category, ItemStack itemStack) {
        boolean over = isCooldownOver(player, category, itemStack);
        if (!over && !player.level().isClientSide) {
            // 播放冷却提示声音，使用原版的声音事件
            player.level().playSound(null, player.blockPosition(), SoundEvents.EXPERIENCE_ORB_PICKUP,
                    SoundSource.PLAYERS, 0.1F, 0.5F);
        }
        return over;
    }

    // ==================== 冷却时间查询方法 ====================

    /**
     * 获取玩家物品剩余冷却时间
     * <p>
     * 获取指定玩家物品的剩余冷却时间。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param itemStack 物品堆
     * @return 剩余冷却时间（tick）
     */
    public static long getRemainingCooldown(Player player, String category, ItemStack itemStack) {
        return getRemainingCooldown(player, CooldownTracker.getCooldownKey(category, itemStack));
    }

    /**
     * 获取玩家剩余冷却时间
     * <p>
     * 获取指定玩家的剩余冷却时间。
     * </p>
     * 
     * @param player 玩家
     * @param category 冷却类别
     * @param identifier 标识符
     * @return 剩余冷却时间（tick）
     */
    public static long getRemainingCooldown(Player player, String category, String identifier) {
        return getRemainingCooldown(player, CooldownTracker.getCooldownKey(category, identifier));
    }

    /**
     * 获取玩家剩余冷却时间
     * <p>
     * 获取指定玩家的剩余冷却时间。
     * </p>
     * 
     * @param player 玩家
     * @param key 冷却键
     * @return 剩余冷却时间（tick）
     */
    public static long getRemainingCooldown(Player player, String key) {
        WorldCooldownManager manager = WorldCooldownManager.get();
        if (manager == null) return 0;

        CooldownTracker tracker = manager.getCooldownTracker(player.getUUID());
        return tracker.getRemainingCooldown(key, player.level().getGameTime());
    }
}